home *** CD-ROM | disk | FTP | other *** search
Text File | 1996-03-21 | 14.7 KB | 571 lines | [TEXT/MPS ] |
- // ===========================================================================
- //
- // GSPicture.c
- //
- // Copyright (C) 1996 Apple Computer, Inc. All rights reserved.
- //
- // ===========================================================================
-
-
- // ===========================================================================
- // Includes
- // ===========================================================================
-
- #include <stdlib.h>
- #include <stdio.h>
-
- #if (kQAPlatform == kQAMacOS)
- #include <Memory.h>
- #include <QuickDraw.h>
- #include <PictUtil.h>
- #endif
-
- #include "RAVE.h"
-
- #include "GSPicture.h"
- #include "GSColorTable.h"
- #include "GSUtilities.h"
- #include "GSError.h"
-
-
- // ===========================================================================
- // Constants
- // ===========================================================================
-
- #if (kQAPlatform == kQAMacOS)
- #define kPICTFileHeaderLength 512
- #endif
-
-
- // ===========================================================================
- // Types
- // ===========================================================================
-
- typedef struct TGSPicture {
- TQAImagePixelType mPixelType;
- long mWidth;
- long mHeight;
- long mRowBytes;
- void* mPixMap;
- TGSColorTable* mColorTable;
- #if (kQAPlatform == kQAMacOS)
- GWorldPtr mGWorld;
- PicHandle mPICTHandle;
- #endif
- } TGSPicture;
-
-
- // ===========================================================================
- // Private Prototypes
- // ===========================================================================
-
- TGSError
- GSPicture_CreateFileStorage(
- TGSPicture* inPicture,
- FILE* inPictureFile);
- TGSError
- GSPicture_DeleteFileStorage(
- TGSPicture* inPicture,
- FILE* inPictureFile);
- TGSError
- GSPicture_ReadFromFile(
- TGSPicture* inPicture,
- FILE* inPictureFile);
- TGSError
- GSPicture_CreatePixMap(
- TGSPicture* inPicture);
-
-
- // ===========================================================================
- // Public Routines
- // ===========================================================================
-
- // ===========================================================================
- // GSPicture_New
- // ===========================================================================
- TGSError
- GSPicture_New(
- TGSPicture** inPicture)
- {
- *inPicture = (TGSPicture*) malloc(sizeof(TGSPicture));
-
- if (*inPicture == nil) {
- return kGSError_NotEnoughMemory;
- }
-
- (**inPicture).mPixelType = kQAPixel_RGB32;
- (**inPicture).mWidth = 0;
- (**inPicture).mHeight = 0;
- (**inPicture).mRowBytes = 0;
- (**inPicture).mPixMap = nil;
- (**inPicture).mColorTable = nil;
- #if (kQAPlatform == kQAMacOS)
- (**inPicture).mGWorld = nil;
- (**inPicture).mPICTHandle = nil;
- #endif
-
- return kGSError_None;
- }
-
-
- // ===========================================================================
- // GSPicture_NewFromPath
- // ===========================================================================
- TGSError
- GSPicture_NewFromPath(
- TGSPicture** inPicture,
- TQAImagePixelType inPixelType,
- const char* inPath)
- {
- FILE* pictureFile;
- TGSError gsError;
-
- // open the file for reading
- pictureFile = fopen(inPath, "rb");
-
- if (pictureFile == nil) {
- return kGSError_FileNotFound;
- }
-
- // now that we have a file pointer, we can call this constructor to
- // actually create the GSPicture
- gsError = GSPicture_NewFromFile(inPicture, inPixelType, pictureFile);
-
- // GSPicture_NewFromFile doesn't close the file itself, so we have to
- fclose(pictureFile);
-
- return gsError;
- }
-
-
- // ===========================================================================
- // GSPicture_NewFromFile
- // ===========================================================================
- TGSError
- GSPicture_NewFromFile(
- TGSPicture** inPicture,
- TQAImagePixelType inPixelType,
- FILE* inPictureFile)
- {
- TGSError gsError;
-
- GSAssert_(inPictureFile);
-
- // initialize the GSPicture structure
- gsError = GSPicture_New(inPicture);
-
- if (gsError != kGSError_None) {
- GSPicture_Delete(*inPicture);
- return gsError;
- }
-
- (**inPicture).mPixelType = inPixelType;
-
- gsError = GSPicture_CreateFileStorage(*inPicture, inPictureFile);
-
- if (gsError != kGSError_None) {
- GSPicture_Delete(*inPicture);
- return gsError;
- }
-
- gsError = GSPicture_ReadFromFile(*inPicture, inPictureFile);
-
- if (gsError != kGSError_None) {
- GSPicture_Delete(*inPicture);
- return gsError;
- }
-
- gsError = GSPicture_CreatePixMap(*inPicture);
-
- if (gsError != kGSError_None) {
- GSPicture_Delete(*inPicture);
- return gsError;
- }
-
- return kGSError_None;
- }
-
-
- // ===========================================================================
- // GSPicture_Delete
- // ===========================================================================
- void
- GSPicture_Delete(
- TGSPicture* inPicture)
- {
- if (inPicture == nil) {
- return;
- }
-
- if (inPicture->mColorTable != nil) {
- GSColorTable_Delete(inPicture->mColorTable);
- inPicture->mColorTable = nil;
- }
-
- #if (kQAPlatform == kQAMacOS)
- // the PICT handle should have been disposed of in DeleteFileStorage,
- // but an error may have occurred before that could happen, which would
- // cause GSPicture_Delete to be called, so we check if we need to
- // dispose of it here, just in case
- if (inPicture->mPICTHandle != nil) {
- KillPicture(inPicture->mPICTHandle);
- inPicture->mPICTHandle = nil;
- }
-
- if (inPicture->mGWorld != nil) {
- DisposeGWorld(inPicture->mGWorld);
- inPicture->mGWorld = nil;
- }
- #endif
-
- // we've disposed of all the memory pointed to by the TGSPicture, so
- // now we can dispose of that struct itself
- free(inPicture);
- }
-
-
- // ===========================================================================
- // GSPicture_GetWidth
- // ===========================================================================
- long
- GSPicture_GetWidth(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mWidth;
- }
-
- // ===========================================================================
- // GSPicture_GetHeight
- // ===========================================================================
- long
- GSPicture_GetHeight(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mHeight;
- }
-
-
- // ===========================================================================
- // GSPicture_GetRowBytes
- // ===========================================================================
- long
- GSPicture_GetRowBytes(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mRowBytes;
- }
-
-
- // ===========================================================================
- // GSPicture_GetPixMap
- // ===========================================================================
- void*
- GSPicture_GetPixMap(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mPixMap;
- }
-
-
- // ===========================================================================
- // GSPicture_GetPixelType
- // ===========================================================================
- TQAImagePixelType
- GSPicture_GetPixelType(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mPixelType;
- }
-
-
- // ===========================================================================
- // GSPicture_GetColorTable
- // ===========================================================================
- TGSColorTable*
- GSPicture_GetColorTable(
- TGSPicture* inPicture)
- {
- GSAssert_(inPicture);
-
- return inPicture->mColorTable;
- }
-
-
- // ===========================================================================
- // Private Routines
- // ===========================================================================
-
- // ===========================================================================
- // GSPicture_CreateFileStorage
- // ===========================================================================
- TGSError
- GSPicture_CreateFileStorage(
- TGSPicture* inPicture,
- FILE* inPictureFile)
- {
- long fileLength = 0;
-
- GSAssert_(inPicture);
- GSAssert_(inPictureFile);
-
- // position the file pointer at the end of the file
- if (fseek(inPictureFile, 0, SEEK_END)) {
- // fseek returns non-zero on error
- return kGSError_FileSystem;
- };
-
- // get the current position of the file pointer, which should be
- // equivalent to the length of the file
- fileLength = ftell(inPictureFile);
-
- if (fileLength == -1L) {
- // ftell returns -1L on error
- return kGSError_FileSystem;
- }
-
- #if (kQAPlatform == kQAMacOS)
- // there is a 512-byte comment header on PICT files which we ignore
- fileLength -= kPICTFileHeaderLength;
-
- // allocate the memory to store the picture from the file
- inPicture->mPICTHandle = (PicHandle) NewHandle(fileLength);
-
- if (inPicture->mPICTHandle == nil) {
- return kGSError_NotEnoughMemory;
- }
- #endif
-
- return kGSError_None;
- }
-
-
- // ===========================================================================
- // GSPicture_DeleteFileStorage
- // ===========================================================================
- TGSError
- GSPicture_DeleteFileStorage(
- TGSPicture* inPicture,
- FILE* inPictureFile)
- {
- GSAssert_(inPicture);
- GSAssert_(inPictureFile);
-
- #if (kQAPlatform == kQAMacOS)
- GSAssert_(inPicture->mPICTHandle);
-
- KillPicture(inPicture->mPICTHandle);
- inPicture->mPICTHandle = nil;
- #endif
-
- return kGSError_None;
- }
-
-
- // ===========================================================================
- // GSPicture_ReadFromFile
- // ===========================================================================
- TGSError
- GSPicture_ReadFromFile(
- TGSPicture* inPicture,
- FILE* inPictureFile)
- {
- long bytesRead = 0;
-
- GSAssert_(inPicture);
- GSAssert_(inPictureFile);
-
- #if (kQAPlatform == kQAMacOS)
- GSAssert_(inPicture->mPICTHandle);
-
- // position the file pointer past the 512-byte PICT header
- if (fseek(inPictureFile, kPICTFileHeaderLength, SEEK_SET)) {
- // fseek returns non-zero on error
- return kGSError_FileSystem;
- };
-
- HLockHi((Handle) inPicture->mPICTHandle);
-
- // read 1 object the size of the PicHandle into the PicHandle
- bytesRead = fread(*inPicture->mPICTHandle, 1,
- GetHandleSize((Handle) inPicture->mPICTHandle), inPictureFile);
-
- HUnlock((Handle) inPicture->mPICTHandle);
-
- if (bytesRead != GetHandleSize((Handle) inPicture->mPICTHandle)) {
- return kGSError_FileSystem;
- }
- #endif
-
- return kGSError_None;
- }
-
-
- // ===========================================================================
- // GSPicture_CreatePixMap
- // ===========================================================================
- TGSError
- GSPicture_CreatePixMap(
- TGSPicture* inPicture)
- {
- #if (kQAPlatform == kQAMacOS)
- TQAColorTableType colorTableType = kQAColorTable_CL8_RGB32;
- PictInfo info;
- short depth = 0;
- short pictInfoVerb = 0;
- short colorsRequested = 0;
-
- GSAssert_(inPicture);
-
- // figure out how deep the GWorld will have to be, and whether we want
- // to extract the PICT's color table
- switch (inPicture->mPixelType) {
- case kQAPixel_RGB32:
- case kQAPixel_ARGB32:
- depth = 32;
- break;
-
- case kQAPixel_RGB16:
- case kQAPixel_ARGB16:
- depth = 16;
- break;
-
- case kQAPixel_CL8:
- colorTableType = kQAColorTable_CL8_RGB32;
- depth = 8;
- pictInfoVerb = returnColorTable;
- colorsRequested = 256;
- break;
-
- case kQAPixel_CL4:
- colorTableType = kQAColorTable_CL4_RGB32;
- depth = 4;
- pictInfoVerb = returnColorTable;
- colorsRequested = 16;
- break;
-
- case kQAPixel_Alpha1:
- depth = 1;
- break;
-
- default:
- GSAssert_(!"Found unrecognized TQAImagePixelType in GSPicture_CreatePixMap.");
- break;
- }
-
- // calc the PICT's height and width. we use GetPictInfo to get the
- // sourceRect of the PICT because that contains the full size of the
- // image and ignores the Hres and Vres values. so we can use the PICT
- // even if it's not 72 dpi. we also get the pict's color table if this
- // is a color table texture, using either 16 or 256 colors and the
- // median method for picking the colors.
- GetPictInfo(inPicture->mPICTHandle, &info, pictInfoVerb, colorsRequested,
- medianMethod, 0);
-
- inPicture->mWidth = info.sourceRect.right - info.sourceRect.left;
- inPicture->mHeight = info.sourceRect.bottom - info.sourceRect.top;
-
- // load the PICT into a new GWorld of the appropriate depth
- {
- CGrafPtr savedPort;
- GDHandle savedDevice;
- Rect pictRect = { 0, 0, 0, 0 };
- QDErr error;
-
- GetGWorld(&savedPort, &savedDevice);
-
- pictRect.right = inPicture->mWidth;
- pictRect.bottom = inPicture->mHeight;
-
- // create an offscreen GWorld of the appropriate size and depth
- error = NewGWorld(&inPicture->mGWorld, depth, &pictRect,
- info.theColorTable, nil, 0);
-
- if (inPicture->mGWorld == nil) {
- // there wasn't enough space to create the GWorld in the app
- // heap, so try system memory
- error = NewGWorld(&inPicture->mGWorld, depth, &pictRect,
- info.theColorTable, nil, useTempMem);
- }
-
- if (inPicture->mGWorld == nil || error != noErr) {
- // we still don't have enough memory to create the GWorld or
- // some other error occurred. before returning, we have to
- // dispose of the color table handle which was possibly
- // allocated for the PICT info.
- if (info.theColorTable != nil) {
- DisposeHandle((Handle) info.theColorTable);
- }
-
- return kGSError_NotEnoughMemory;
- }
-
- // prepare to work with the GWorld
- SetGWorld(inPicture->mGWorld, nil);
-
- SetOrigin(0, 0);
-
- // prepare to draw into the GWorld. we'll leave the pixels locked
- // even after we're finished drawing because we use the GWorld as
- // a pixmap to create a texture, so we don't want it to move.
- if (LockPixels(GetGWorldPixMap(inPicture->mGWorld)) != true) {
- return kGSError_OS;
- }
-
- EraseRect(&pictRect);
-
- // draw the PICT into the GWorld
- DrawPicture(inPicture->mPICTHandle, &pictRect);
-
- if (depth == 1) {
- // in a 1-bit GWorld, 1 == black and 0 == white, which is the
- // opposite of what we want, so invert the bitmap
- InvertRect(&pictRect);
- }
-
- // revert to the previous GWorld
- SetGWorld(savedPort, savedDevice);
-
- // we've drawn the picture, so we can get rid of the handle now
- KillPicture(inPicture->mPICTHandle);
- inPicture->mPICTHandle = nil;
- }
-
- // to get the pixmap's actual rowbytes, we have to mask off the top two bits
- inPicture->mRowBytes = (**(GetGWorldPixMap(inPicture->mGWorld))).rowBytes & 0x3fff;
-
- // save the GWorld's base address
- inPicture->mPixMap = GetPixBaseAddr(GetGWorldPixMap(inPicture->mGWorld));
-
- if (pictInfoVerb == returnColorTable) {
- // this is a CL4 or CL8 texture, so we have to create a TGSColorTable
- // out of the CTabHandle we extracted from the PICT
- TGSError gsError;
-
- GSAssert_(info.theColorTable);
-
- gsError = GSColorTable_NewFromMacColorTable(&inPicture->mColorTable,
- colorTableType, info.theColorTable);
-
- // GetPictInfo creates a color table handle which we're responsible
- // for disposing of
- DisposeHandle((Handle) info.theColorTable);
-
- if (gsError != kGSError_None) {
- return gsError;
- }
- }
- #endif
-
- return kGSError_None;
- }
-